﻿using MicroDb;
using MicroDb.Querys;

using Microsoft.Extensions.Caching.Memory;

using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Linq.Expressions;
using System.Reflection;
using System.Threading.Tasks;
using System.Xml.Linq;

namespace System.Linq
{
    public static class QueryableExtension
    {

        private static IMemoryCache GetMemoryCache(this IQueryProvider queryProvider)
        {
            if (queryProvider is DBQueryProvider dBQueryProvider)
            {
                return dBQueryProvider.MemoryCache;
            }
            return null;
        }



        /// <summary>
        /// IQueryable 查询为 Dictionary
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <typeparam name="TKey"></typeparam>
        /// <typeparam name="TElement"></typeparam>
        /// <param name="source"></param>
        /// <param name="keySelector"></param>
        /// <param name="elementSelector"></param>
        /// <returns></returns>
        public static Dictionary<TKey, TElement> ToDictionary<TSource, TKey, TElement>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector, Expression<Func<TSource, TElement>> elementSelector)
        {
            var param = keySelector.Parameters;

            var constructor = typeof(KeyValuePair<TKey, TElement>).GetConstructors().FirstOrDefault();

            var newinit = Expression.New(constructor, keySelector.Body, elementSelector.Body);
            return source.Select(Expression.Lambda<Func<TSource, KeyValuePair<TKey, TElement>>>(newinit, param))
                  .ToList()
                  .ToDictionary(a => a.Key, a => a.Value);
        }

        /// <summary>
        /// 查询第一个属性
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="source"></param>
        /// <param name="selector"></param>
        /// <returns></returns>
        public static TResult FirstField<TSource, TResult>(this IQueryable<TSource> source, Expression<Func<TSource, TResult>> selector)
        {
            return source.Select(selector).FirstOrDefault();
        }


        public static TResult FirstField<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector)
        {
            return source.Select(selector).FirstOrDefault();
        }

        public static TSource GetModelBy<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate)
        {
            return source.Where(predicate).FirstOrDefault();
        }

        public static TSource GetModelBy<TSource, K>(this IQueryable<TSource> source, K primaryKey)
        {
            var type = typeof(TSource);
            var propertyInfo = GetPrimaryKey(typeof(K));
            var parameter = Expression.Parameter(type, "a");
            return source.GetModelBy(Expression.Lambda<Func<TSource, bool>>(Expression.Equal(Expression.Property(parameter, propertyInfo), Expression.Constant(primaryKey)), parameter));
        }

        #region 增改数据

        /// <summary>
        /// 添加一条数据
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <param name="source"></param>
        /// <param name="insert"> </param>
        /// <returns></returns>
        public static bool Add<TSource>(this IQueryable<TSource> source, TSource insert)
        {
            Expression[] arguments = new Expression[] { source.Expression, Expression.Constant(insert) };
            var f = new Func<IQueryable<TSource>, TSource, bool>(Add<TSource>);
            return source.Provider.Execute<bool>(Expression.Call(null, f.Method, arguments));
        }

        /// <summary>
        /// 批量添加
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <param name="source"></param>
        /// <param name="insert"></param>
        /// <returns></returns>
        public static bool AddRange<TSource>(this IQueryable<TSource> source, IEnumerable<TSource> inserts)
        {
            if (inserts == null || inserts.Count() == 0)
            {
                return false;
            }
            Expression[] arguments = new Expression[] { source.Expression, Expression.Constant(inserts.ToArray()) };
            var f = new Func<IQueryable<TSource>, TSource[], bool>(AddRange);
            return source.Provider.Execute<bool>(Expression.Call(null, f.Method, arguments));
        }

        /// <summary>
        /// 添加或更新数据
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <param name="source"></param>
        /// <param name="insert"></param>
        /// <returns></returns>
        public static bool AddOrUpdate<TSource>(this IQueryable<TSource> source, TSource insert)
        {
            Expression[] arguments = new Expression[] { source.Expression, Expression.Constant(insert) };
            var f = new Func<IQueryable<TSource>, TSource, bool>(AddOrUpdate<TSource>);
            return source.Provider.Execute<bool>(Expression.Call(null, f.Method, arguments));
        }


        /// <summary>
        /// 更新部分字段
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <param name="source"></param>
        /// <param name="updateSelector"></param>
        /// <returns></returns>
        public static bool UpdateColumns<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, TSource>> updateSelector)
        {
            if (source == null)
            {
                throw new ArgumentNullException("source");
            }
            if (updateSelector == null)
            {
                throw new ArgumentNullException("updateSelector");
            }
            Expression[] arguments = new Expression[] { source.Expression, Expression.Quote(updateSelector) };
            var f = new Func<IQueryable<TSource>, Expression<Func<TSource, TSource>>, bool>(UpdateColumns<TSource>);
            return source.Provider.Execute<bool>(Expression.Call(null, f.Method, arguments));
        }

        /// <summary>
        /// 更新所有字段
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <param name="source"></param>
        /// <param name="model"></param>
        /// <returns></returns>
        public static bool Update<TSource>(this IQueryable<TSource> source, TSource model)
        {
            if (source == null)
            {
                throw new ArgumentNullException("source");
            }
            Expression[] arguments = new Expression[] { source.Expression, Expression.Constant(model) };
            var f = new Func<IQueryable<TSource>, TSource, bool>(Update<TSource>);
            return source.Provider.Execute<bool>(Expression.Call(null, f.Method, arguments));
        }


        #endregion

        #region 删除数据

        /// <summary>
        /// 删除数据
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <param name="source"></param>
        /// <returns></returns>
        public static bool Delete<TSource>(this IQueryable<TSource> source)
        {
            Expression[] arguments = new Expression[] { source.Expression };
            var f = new Func<IQueryable<TSource>, bool>(Delete<TSource>);
            return source.Provider.Execute<bool>(Expression.Call(null, f.Method, arguments));
        }

        /// <summary>
        /// 删除数据
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <param name="source"></param>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public static bool Delete<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate)
        {
            return source.Where(predicate).Delete();
        }

        public static bool Delete<TSource, K>(this IQueryable<TSource> source, K primaryKey)
        {
            var type = typeof(TSource);
            var propertyInfo = GetPrimaryKey(typeof(K));
            var parameter = Expression.Parameter(type, "a");
            return source.Where(Expression.Lambda<Func<TSource, bool>>(Expression.Equal(Expression.Property(parameter, propertyInfo), Expression.Constant(primaryKey)), parameter)).Delete();
        }

        #endregion


        /// <summary>
        /// 分表 表后缀
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <param name="source"></param>
        /// <param name="suffix">表后缀</param>
        /// <returns></returns>
        public static IQueryable<TSource> Suffix<TSource>(this IQueryable<TSource> source, string suffix)
        {
            if (string.IsNullOrEmpty(suffix))
            {
                return source;
            }
            Expression[] arguments = new Expression[] { source.Expression, Expression.Constant(suffix) };
            var f = new Func<IQueryable<TSource>, string, IQueryable<TSource>>(Suffix);
            return source.Provider.CreateQuery<TSource>(Expression.Call(null, f.Method, arguments));
        }

        /// <summary>
        /// 分表 表后缀,如果表不存在则创建
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <param name="source"></param>
        /// <param name="suffix">表后缀</param>
        /// <returns></returns>
        public static IQueryable<TSource> SuffixAutoCreate<TSource>(this IQueryable<TSource> source, string suffix)
        {
            if (string.IsNullOrEmpty(suffix))
            {
                return source;
            }
            Expression[] arguments = new Expression[] { source.Expression, Expression.Constant(suffix) };
            var f = new Func<IQueryable<TSource>, string, IQueryable<TSource>>(SuffixAutoCreate);
            return source.Provider.CreateQuery<TSource>(Expression.Call(null, f.Method, arguments));
        }
        /// <summary>
        /// 检查是否存在
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static bool Exists<TSource>(this IQueryable<TSource> source)
        {
            return source.Count() > 0;
        }

        /// <summary>
        /// 检查是否存在
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static bool Exists<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate)
        {
            return source.Where(predicate).Count() > 0;
        }

        #region Where条件

        public static IQueryable<TSource> Where<TSource, Key>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate, Key? condition) where Key : struct
        {
            if (condition.HasValue)
            {
                return source.Where(predicate);
            }
            return source;
        }


        /// <summary>
        /// Where条件
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <param name="source"></param>
        /// <param name="predicate"></param>
        /// <param name="condition"></param>
        /// <returns></returns>
        public static IQueryable<TSource> Where<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate, bool condition)
        {
            if (condition)
            {
                return source.Where(predicate);
            }
            return source;
        }

        /// <summary>
        /// Where条件
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <param name="source"></param>
        /// <param name="predicate"></param>
        /// <param name="condition">当condition不等于空或Null 执行条件</param>
        /// <returns></returns>
        public static IQueryable<TSource> Where<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate, string condition)
        {
            return source.Where(predicate, !string.IsNullOrEmpty(condition));
        }



        /// <summary>
        /// Where条件
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <param name="source"></param>
        /// <param name="predicate"></param>
        /// <param name="condition">当condition大于 0 时 执行条件</param>
        /// <returns></returns>
        public static IQueryable<TSource> Where<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate, int condition)
        {
            return source.Where(predicate, condition > 0);
        }

        /// <summary>
        /// 自定义查询
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <param name="source"></param>
        /// <param name="whereSelector">映射的条件</param>
        /// <returns></returns>
        public static IQueryable<TSource> WhereCustom<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, string>> whereSelector)
        {
            if (source == null)
            {
                throw new ArgumentNullException("source");
            }
            if (whereSelector == null)
            {
                throw new ArgumentNullException("whereSelector");
            }
            Expression[] arguments = new Expression[] { source.Expression, Expression.Quote(whereSelector) };
            var f = new Func<IQueryable<TSource>, Expression<Func<TSource, string>>, IQueryable<TSource>>(WhereCustom);
            return source.Provider.CreateQuery<TSource>(Expression.Call(null, f.Method, arguments));
        }

        public static IQueryable<TSource> WhereCustom<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, string>> whereSelector, bool condition)
        {
            if (condition)
            {
                return WhereCustom(source, whereSelector);
            }
            return source;
        }
        public static IQueryable<TSource> WhereCustom<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, string>> whereSelector, string condition)
        {
            return WhereCustom(source, whereSelector, !string.IsNullOrEmpty(condition));
        }
        public static IQueryable<TSource> WhereCustom<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, string>> whereSelector, int condition)
        {
            return WhereCustom(source, whereSelector, condition > 0);
        }
        /// <summary>
        /// 自定义查询
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <typeparam name="Key"></typeparam>
        /// <param name="source"></param>
        /// <param name="whereSelector"></param>
        /// <param name="condition"></param>
        /// <returns></returns>
        public static IQueryable<TSource> WhereCustom<TSource, Key>(this IQueryable<TSource> source, Expression<Func<TSource, string>> whereSelector, Key? condition) where Key : struct
        {
            return WhereCustom(source, whereSelector, condition.HasValue);
        }
        public static IQueryable<TSource> WhereGroup<TSource>(this IQueryable<TSource> source, Action<WhereAppend<TSource>> action, int condition) => WhereGroup(source, action, condition > 0);
        public static IQueryable<TSource> WhereGroup<TSource>(this IQueryable<TSource> source, Action<WhereAppend<TSource>> action, string condition) => WhereGroup(source, action, !string.IsNullOrEmpty(condition));

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <param name="source"></param>
        /// <param name="action"></param>
        /// <param name="condition"></param>
        /// <returns></returns>
        public static IQueryable<TSource> WhereGroup<TSource>(this IQueryable<TSource> source, Action<WhereAppend<TSource>> action, bool condition)
        {
            if (condition)
            {
                return WhereGroup(source, action);
            }
            return source;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <param name="source"></param>
        /// <param name="action"></param>
        /// <returns></returns>
        public static IQueryable<TSource> WhereGroup<TSource>(this IQueryable<TSource> source, Action<WhereAppend<TSource>> action)
        {
            var where = new WhereAppendCreate<TSource>();
            action(where);
            return where.Build(source);

        }

        #endregion

        /// <summary>
        /// 筛选聚合查询
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <param name="source"></param>
        /// <param name="selector"></param>
        /// <returns></returns>
        /// <example>
        /// <code lang="c#">
        /// <![CDATA[
        /// .SelectAggregate(a => new 
        ///  { 
        ///  max = a.Max(a => a.createTime),
        ///  min = a.Min(a => a.createTime)
        ///  });
        /// 
        /// ]]>
        /// </code>
        /// </example>
        public static TResult SelectAggregate<TSource, TResult>(this IQueryable<TSource> source, Expression<Func<IEnumerable<TSource>, TResult>> selector)
        {
            Expression[] arguments = new Expression[] { source.Expression, Expression.Quote(selector) };
            var f = new Func<IQueryable<TSource>, Expression<Func<IEnumerable<TSource>, TResult>>, TResult>(SelectAggregate);
            return source.Provider.Execute<TResult>(Expression.Call(null, f.Method, arguments));
        }

        /// <summary>
        /// 根据条件查询，删除添加或更新
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="EK"></typeparam>
        /// <param name="source"></param>
        /// <param name="inner">新的数据</param>
        /// <param name="queryPredicate">查询条件</param>
        /// <param name="commp">更新对比</param>
        public static void Merge<T, EK>(this IQueryable<T> source, IEnumerable<T> inner, Expression<Func<T, bool>> queryPredicate, Func<T, EK> commp)
        {
            var type = typeof(T);
            var propertyInfo = GetPrimaryKey(type);
            var method = typeof(QueryableExtension).GetMethod(nameof(CreatePrimaryKeyExpression), BindingFlags.Static | BindingFlags.NonPublic);
            var result = method.MakeGenericMethod(type, propertyInfo.PropertyType).Invoke(null, new object[] { type, propertyInfo });
            var method2 = typeof(QueryableExtension).GetMethod(nameof(Merge), BindingFlags.Static | BindingFlags.NonPublic);
            method2.MakeGenericMethod(type, typeof(EK), propertyInfo.PropertyType).Invoke(null, new object[] { source, inner, queryPredicate, commp, result });
        }

        private static Expression<Func<T, PK>> CreatePrimaryKeyExpression<T, PK>(Type type, PropertyInfo propertyInfo)
        {
            var parameter = Expression.Parameter(type, "a");
            return Expression.Lambda<Func<T, PK>>(Expression.Property(parameter, propertyInfo), parameter);
        }


        private static void Merge<T, EK, PK>(this IQueryable<T> source, IEnumerable<T> inner, Expression<Func<T, bool>> queryPredicate, Func<T, EK> commp, Expression<Func<T, PK>> primaryKey)
        {

            var oldList = source.Where(queryPredicate).ToList();

            var deleteIds = oldList.ExceptBy(inner, commp).Select(a => primaryKey.Compile().Invoke(a)).ToArray();

            // 差集
            var appends = inner.ExceptBy(oldList, commp).ToArray();

            // 交集
            var updates = oldList.IntersectBy(inner, commp).ToArray();


            if (deleteIds.Length > 0)
                source.Delete(CreateWhereContainsPrimaryKey(deleteIds, primaryKey));

            if (appends.Length > 0)
                source.AddRange(appends);

            foreach (var item in updates)
            {
                var update = inner.FirstOrDefault(a => commp(a).Equals(commp(item)));
                PK p = primaryKey.Compile().Invoke(item);
                source.Where(CreateWherePrimaryKey(p, primaryKey)).Update(update);
            }
        }

        private static Expression<Func<T, bool>> CreateWherePrimaryKey<T, K>(K primaryKey, Expression<Func<T, K>> propertyInfo)
        {
            return Expression.Lambda<Func<T, bool>>(Expression.Equal(Expression.Constant(primaryKey), propertyInfo.Body), propertyInfo.Parameters.FirstOrDefault());
        }

        /// <summary>
        /// 获取主键
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        private static PropertyInfo GetPrimaryKey(Type type)
        {
            var properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public);
            foreach (var property in properties)
            {
                var column = property.GetCustomAttribute<PrimaryAttribute>(true);
                if (column != null)
                {
                    return property;
                }
            }
            throw new InvalidCastException("缺少主键");

        }
        private static Expression<Func<T, bool>> CreateWhereContainsPrimaryKey<T, K>(K[] primaryKey, Expression<Func<T, K>> propertyInfo)
        {
            var f = new Func<IEnumerable<K>, K, bool>(Enumerable.Contains);
            return Expression.Lambda<Func<T, bool>>(Expression.Call(f.Method, Expression.Constant(primaryKey), propertyInfo.Body), propertyInfo.Parameters.FirstOrDefault());
        }


        #region 排序

        /// <summary>
        /// 排序
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <typeparam name="TKey"></typeparam>
        /// <param name="source"></param>
        /// <param name="keySelector"></param>
        /// <param name="condition">是否排序</param>
        /// <returns></returns>
        public static IQueryable<TSource> OrderBy<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector, bool condition)
        {
            if (condition)
            {
                return source.OrderBy(keySelector);
            }
            return source;
        }


        public static IQueryable<TSource> OrderBy<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector, OrderType orderType)
        {
            switch (orderType)
            {
                case OrderType.Asc:
                    return source.OrderBy(keySelector);
                case OrderType.Desc:
                    return source.OrderByDescending(keySelector);
                default:
                    return source;
            }
        }
        /// <summary>
        /// 降序排序
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <typeparam name="TKey"></typeparam>
        /// <param name="source"></param>
        /// <param name="keySelector"></param>
        /// <param name="condition"></param>
        /// <returns></returns>
        public static IQueryable<TSource> OrderByDescending<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector, bool condition)
        {
            if (condition)
            {
                return source.OrderByDescending(keySelector);
            }
            return source;
        }

        /// <summary>
        /// 随机排序
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <param name="source"></param>
        /// <returns></returns>
        public static IQueryable<TSource> OrderByRand<TSource>(this IQueryable<TSource> source)
        {
            Expression[] arguments = new Expression[] { source.Expression };
            var f = new Func<IQueryable<TSource>, IQueryable<TSource>>(OrderByRand);
            return source.Provider.CreateQuery<TSource>(Expression.Call(null, f.Method, arguments));
        }

        /// <summary>
        /// 随机排序
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <param name="source"></param>
        /// <returns></returns>
        public static IQueryable<TSource> OrderByRand<TSource>(this IQueryable<TSource> source, bool condition)
        {
            if (condition)
            {
                return source.OrderByRand();
            }
            return source;
        }


        #endregion

        /// <summary>
        /// 异步查询结果
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <typeparam name="TKey"></typeparam>
        /// <param name="source"></param>
        /// <returns></returns>
        public static Task<List<TSource>> ToListAsync<TSource>(this IQueryable<TSource> source)
        {
            return Task.Run(() => source.ToList());
        }

        /// <summary>
        /// 获取分页
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <param name="filter"></param>
        /// <returns></returns>
        public static List<T> GetPage<T>(this IQueryable<T> source, IQueryFilter filter)
        {
            return source.Skip(filter.Skip).Take(filter.Take).ToList();
        }

        /// <summary>
        /// 载入分页器
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <param name="source"></param>
        /// <param name="skip"></param>
        /// <param name="take"></param>
        /// <returns></returns>
        public static List<TSource> GetPage<TSource>(this IQueryable<TSource> source, int skip, int take)
        {
            return source.Skip(skip).Take(take).ToList();
        }

        /// <summary>
        /// 分页查询并返回条数
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <param name="filter"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public static List<T> GetPage<T>(this IQueryable<T> source, IQueryFilter filter, out int count)
        {
            count = source.Count();
            if (count > 0)
                return source.GetPage(filter).ToList();
            return new List<T>();
        }

        /// <summary>
        /// 分页查询并返回条数
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <param name="offset"></param>
        /// <param name="size"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public static List<T> GetPage<T>(this IQueryable<T> source, int offset, int size, out int count)
        {
            count = source.Count();
            if (count > 0)
                return source.GetPage(offset, size).ToList();
            return new List<T>();
        }

        #region 2 表连接

        public static IJoinStartQueryable<T1, T2> InnerJoin<T1, T2>(this IQueryable<T1> source, IQueryable<T2> source2, Expression<Func<T1, T2, bool>> onPredicate)
        {
            return new DBJoinQueryable<T1, T2>(source, source2, JoinType.INNER).On(onPredicate);
        }

        public static IJoinStartQueryable<T1, T2> LeftJoin<T1, T2>(this IQueryable<T1> source, IQueryable<T2> source2, Expression<Func<T1, T2, bool>> onPredicate)
        {
            return new DBJoinQueryable<T1, T2>(source, source2, JoinType.LEFT).On(onPredicate);
        }

        public static IJoinStartQueryable<T1, T2> RightJoin<T1, T2>(this IQueryable<T1> source, IQueryable<T2> source2, Expression<Func<T1, T2, bool>> onPredicate)
        {
            return new DBJoinQueryable<T1, T2>(source, source2, JoinType.RIGHT).On(onPredicate);
        }

        public static IJoinQueryable<T1, T2> Where<T1, T2>(this IJoinQueryable<T1, T2> source, Expression<Func<T1, T2, bool>> predicate, bool condition)
        {
            if (!condition)
            {
                return source;
            }
            return source.Where(predicate);
        }
        public static IJoinQueryable<T1, T2> Where<T1, T2>(this IJoinQueryable<T1, T2> source, Expression<Func<T1, T2, bool>> predicate, string condition)
        {
            return source.Where(predicate, !string.IsNullOrEmpty(condition));
        }
        #endregion
        #region 3 表连接
        public static IJoinStartQueryable<T1, T2, T3> InnerJoin<T1, T2, T3>(this IJoinStartQueryable<T1, T2> source, IQueryable<T3> source2, Expression<Func<T1, T2, T3, bool>> onPredicate)
        {
            return source.Join(source2, JoinType.INNER).On(onPredicate);
        }

        public static IJoinStartQueryable<T1, T2, T3> LeftJoin<T1, T2, T3>(this IJoinStartQueryable<T1, T2> source, IQueryable<T3> source2, Expression<Func<T1, T2, T3, bool>> onPredicate)
        {
            return source.Join(source2, JoinType.LEFT).On(onPredicate);
        }

        public static IJoinStartQueryable<T1, T2, T3> RightJoin<T1, T2, T3>(this IJoinStartQueryable<T1, T2> source, IQueryable<T3> source2, Expression<Func<T1, T2, T3, bool>> onPredicate)
        {
            return source.Join(source2, JoinType.RIGHT).On(onPredicate);
        }

        public static IJoinQueryable<T1, T2, T3> Where<T1, T2, T3>(this IJoinQueryable<T1, T2, T3> source, Expression<Func<T1, T2, T3, bool>> predicate, bool condition)
        {
            if (!condition)
            {
                return source;
            }
            return source.Where(predicate);
        }

        #endregion

        #region 4 表连接
        public static IJoinStartQueryable<T1, T2, T3, T4> InnerJoin<T1, T2, T3, T4>(this IJoinStartQueryable<T1, T2, T3> source, IQueryable<T4> source2, Expression<Func<T1, T2, T3, T4, bool>> onPredicate)
        {
            return source.Join(source2, JoinType.INNER).On(onPredicate);
        }

        public static IJoinStartQueryable<T1, T2, T3, T4> LeftJoin<T1, T2, T3, T4>(this IJoinStartQueryable<T1, T2, T3> source, IQueryable<T4> source2, Expression<Func<T1, T2, T3, T4, bool>> onPredicate)
        {
            return source.Join(source2, JoinType.LEFT).On(onPredicate);
        }

        public static IJoinStartQueryable<T1, T2, T3, T4> RightJoin<T1, T2, T3, T4>(this IJoinStartQueryable<T1, T2, T3> source, IQueryable<T4> source2, Expression<Func<T1, T2, T3, T4, bool>> onPredicate)
        {
            return source.Join(source2, JoinType.RIGHT).On(onPredicate);
        }

        public static IJoinQueryable<T1, T2, T3, T4> Where<T1, T2, T3, T4>(this IJoinQueryable<T1, T2, T3, T4> source, Expression<Func<T1, T2, T3, T4, bool>> predicate, bool condition)
        {
            if (!condition)
            {
                return source;
            }
            return source.Where(predicate);
        }
        public static IJoinQueryable<T1, T2, T3, T4> Where<T1, T2, T3, T4>(this IJoinQueryable<T1, T2, T3, T4> source, Expression<Func<T1, T2, T3, T4, bool>> predicate, string condition)
        {
            return source.Where(predicate, !string.IsNullOrEmpty(condition));
        }

        #endregion

        #region 4 表连接
        public static IJoinStartQueryable<T1, T2, T3, T4, T5> InnerJoin<T1, T2, T3, T4, T5>(this IJoinStartQueryable<T1, T2, T3, T4> source, IQueryable<T5> source2, Expression<Func<T1, T2, T3, T4, T5, bool>> onPredicate)
        {
            return source.Join(source2, JoinType.INNER).On(onPredicate);
        }

        public static IJoinStartQueryable<T1, T2, T3, T4, T5> LeftJoin<T1, T2, T3, T4, T5>(this IJoinStartQueryable<T1, T2, T3, T4> source, IQueryable<T5> source2, Expression<Func<T1, T2, T3, T4, T5, bool>> onPredicate)
        {
            return source.Join(source2, JoinType.LEFT).On(onPredicate);
        }

        public static IJoinStartQueryable<T1, T2, T3, T4, T5> RightJoin<T1, T2, T3, T4, T5>(this IJoinStartQueryable<T1, T2, T3, T4> source, IQueryable<T5> source2, Expression<Func<T1, T2, T3, T4, T5, bool>> onPredicate)
        {
            return source.Join(source2, JoinType.RIGHT).On(onPredicate);
        }

        public static IJoinQueryable<T1, T2, T3, T4, T5> Where<T1, T2, T3, T4, T5>(this IJoinQueryable<T1, T2, T3, T4, T5> source, Expression<Func<T1, T2, T3, T4, T5, bool>> predicate, bool condition)
        {
            if (!condition)
            {
                return source;
            }
            return source.Where(predicate);
        }
        public static IJoinQueryable<T1, T2, T3, T4, T5> Where<T1, T2, T3, T4, T5>(this IJoinQueryable<T1, T2, T3, T4, T5> source, Expression<Func<T1, T2, T3, T4, T5, bool>> predicate, string condition)
        {
            return source.Where(predicate, !string.IsNullOrEmpty(condition));
        }
        #endregion
        public static int ExecuteNonQuery(this SqlExecute sqlExecute, string commandText, params (string, object)[] parameters)
        {
            return sqlExecute.ExecuteNonQuery(CommandType.Text, commandText, parameters.ToDictionary(a => a.Item1, a => a.Item2));
        }

        public static object ExecuteScalar(this SqlExecute sqlExecute, string commandText, params (string, object)[] parameters)
        {
            return sqlExecute.ExecuteScalar(CommandType.Text, commandText, parameters.ToDictionary(a => a.Item1, a => a.Item2));
        }

        public static List<T> ExecuteList<T>(this SqlExecute sqlExecute, string commandText, params (string, object)[] parameters)
        {
            return sqlExecute.ExecuteList<T>(CommandType.Text, commandText, parameters.ToDictionary(a => a.Item1, a => a.Item2));
        }


        /// <summary>
        /// 缓存中读取
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <typeparam name="TKey"></typeparam>
        /// <param name="source"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static List<TSource> ToListFromCache<TSource>(this IQueryable<TSource> source, object key, int timeout = 300)
        {
            var cacheMemory = source.Provider.GetMemoryCache();
            if (cacheMemory == null)
            {
                return source.ToList();
            }
            return cacheMemory.GetOrCreate(key, c =>
            {
                c.SetSlidingExpiration(TimeSpan.FromSeconds(timeout));
                return source.ToList();
            });
        }
        /// <summary>
        /// 缓存中读取
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <param name="source"></param>
        /// <param name="key"></param>
        /// <param name="timeout"></param>
        /// <returns></returns>
        public static TSource[] ToArrayFromCache<TSource>(this IQueryable<TSource> source, object key, int timeout = 300)
        {
            var cacheMemory = source.Provider.GetMemoryCache();
            if (cacheMemory == null)
            {
                return source.ToArray();
            }
            return cacheMemory.GetOrCreate(key, c =>
            {
                c.SetSlidingExpiration(TimeSpan.FromSeconds(timeout));
                return source.ToArray();
            });
        }
        /// <summary>
        /// 从缓存读取字典
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <typeparam name="TKey"></typeparam>
        /// <typeparam name="TElement"></typeparam>
        /// <param name="source"></param>
        /// <param name="keySelector"></param>
        /// <param name="elementSelector"></param>
        /// <param name="key"></param>
        /// <param name="timeout"></param>
        /// <returns></returns>
        public static Dictionary<TKey, TElement> ToToDictionaryFromCache<TSource, TKey, TElement>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector, Expression<Func<TSource, TElement>> elementSelector, object key, int timeout = 3600)
        {
            var cacheMemory = source.Provider.GetMemoryCache();
            if (cacheMemory == null)
            {
                return source.ToDictionary(keySelector, elementSelector);
            }
            return cacheMemory.GetOrCreate(key, c =>
            {
                c.SetSlidingExpiration(TimeSpan.FromSeconds(timeout));
                return source.ToDictionary(keySelector, elementSelector);
            });
        }
        /// <summary>
        /// 清除缓存
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <param name="source"></param>
        /// <param name="key"></param>
        public static void RemoveCache<TSource>(this IQueryable<TSource> source, object key)
        {
            var cacheMemory = source.Provider.GetMemoryCache();
            if (cacheMemory != null)
            {
                cacheMemory.Remove(key);
            }
        }
    }

}
